package hasthi.tools.analyze;

import hasthi.common.HasthiException;
import hasthi.common.HasthiException.FaultCode;
import hasthi.test.ParserProfileDocument;
import hasthi.test.ParserProfileDocument.ParserProfile;
import hasthi.test.ParserProfileDocument.ParserProfile.DataSpec;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.text.DecimalFormat;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PerfDataParser {
    private static HashMap<String, Experiment> experimentMap = new HashMap<String, Experiment>();
    private static DecimalFormat df = new DecimalFormat(".0");
    private boolean printUnporcessedLines = false;
    
    private boolean writeRawData = true;

    public static void main(String[] args) throws Exception {
        PerfDataParser hasthiData = new PerfDataParser();

        ParserProfileDocument parserProfileDocument = ParserProfileDocument.Factory.parse(new File(
                args[0]));
        if (!parserProfileDocument.validate()) {
            throw new HasthiException("Profile is not valied", FaultCode.InitalizationError);
        }
        ParserProfile parserProfile = parserProfileDocument.getParserProfile();
        Pattern expPattern = Pattern.compile(parserProfile.getExpPattern());
        File baseDir = new File(args[1]);
        if (!parserProfile.getDirBased()) {
            hasthiData.parseDataFiles(baseDir, expPattern,parserProfile.getDataSpecArray());
        } else {
            hasthiData.parseDataDirs(baseDir, expPattern, parserProfile.getDataSpecArray());
        }
        hasthiData.printResults(baseDir.getAbsolutePath());
    }

    public static boolean testRegex(Pattern pattern, String str) {
        return pattern.matcher(str).matches();
    }

    public void printResults(String file) throws Exception {
        
        Set<String> keys = new TreeSet<String>(new Comparator<String>() {
            public int compare(String o1, String o2) {
                String[] set1 = o1.split("_");
                String[] set2 = o2.split("_");

                if ((set1.length == set2.length)) {
                    int compareIndex = 0;
                    while(compareIndex < set1.length){
                        double val1 = Double.parseDouble(set1[compareIndex]);
                        double val2 = Double.parseDouble(set2[compareIndex]);
                        if (val1 != val2) {
                            return (val1 - val2 > 0)?+1:-1;
                        } else {
                            compareIndex++;
                        }
                        
                    }
                }
                return 0;
            }

        });
        keys.addAll(experimentMap.keySet());
        
        for (String key : keys) {
            experimentMap.get(key).processData();
        }
        
        
        
        Map<String, StringBuffer> dataByManagerCount = new HashMap<String, StringBuffer>();
        System.out.println("========================== Results ================================");
        System.out.println("");
        
        boolean isFirst = true;
        
        FormattedTable table = null; 
        for(String key:keys){
            Experiment datastr = experimentMap.get(key);
            if(isFirst){
                isFirst=false;
                table = new FormattedTable(datastr.getHeader());
            }
            table.addLine(key+"\t"+datastr);
        }
        System.out.println(table.toString());
        
        System.out.println("===================================================================");
        for (String key : keys) {
            System.out.println(experimentMap.get(key).printdetails(key));
        }
//        File f = new File("/u/hperera/logs/hasthi_data");
//        f.mkdirs();
//        for (String managerCount : dataByManagerCount.keySet()) {
//            FileWriter out = new FileWriter(new File(f, "mng" + managerCount + ".data"));
//            out.write("#RCount\tCLE2E\tMngHB\tMM\tCM\tAHB\tMLE2E\tCLCi\tMHBCi\tAHBci\tMLCi\n");
//            out.write(dataByManagerCount.get(managerCount).toString());
//            out.close();
//        }
        
        if(writeRawData){
            File baseDir = new File(file);
            File targetDir;
            if(baseDir.isDirectory()){
                targetDir = new File(file,"data");
            }else{
                targetDir = new File("data");
            }
            
            targetDir.mkdir();
            for (String key : keys) {
                Experiment exp = experimentMap.get(key);
                exp.writeRowData(new File(targetDir,key+".data"));
            }
        }
        
    }

    public void parseDataDirs(File dir, Pattern pattern, DataSpec[] specs) throws Exception {
        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            Matcher matcher = pattern.matcher(files[i].getName());
            if (matcher.matches() && files[i].isDirectory()) {
                int groupCount = matcher.groupCount();
                String key = "";
                if (groupCount == 0) {
                    key = files[i].getName();
                } else {
                    key =  matcher.group(1);
                    for (int j = 1; j < groupCount; j++) {
                        key = key + "_" + matcher.group(j + 1);
                    }
                }
                
                parseDataDir(key, files[i], specs);
            }else{
                System.out.println(files[i].getName() + " not matched" );    
            }
        }
    }

    public void parseDataDir(String key, File dir, DataSpec[] specs) throws Exception {
        Experiment experiment = experimentMap.get(key);
        if (experiment == null) {
            experiment = new Experiment();
            experimentMap.put(key, experiment);
        }
        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            for (DataSpec spec : specs) {
                Pattern filePattern = Pattern.compile(spec.getFilepattern());
                Pattern dataPattern = Pattern.compile(spec.getDataPattern());
                Matcher matcher = filePattern.matcher(files[i].getName());
                if (matcher.matches()) {
                    parseFile(files[i], experiment, dataPattern, spec.getKeyArray(),spec.getMulitpleDataValues());
                }
            }
        }
        System.out.println(key + "completed" + experimentMap);
    }

    public void parseDataFiles(File dir, Pattern expPattern,DataSpec[] specs) throws Exception {
        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            for (DataSpec spec : specs) {
                Pattern filePattern = Pattern.compile(spec.getFilepattern());
                Pattern dataPattern = Pattern.compile(spec.getDataPattern());
                Matcher matcher = filePattern.matcher(files[i].getName());
                Matcher expMatcher = expPattern.matcher(files[i].getName());
                if (matcher.matches() && expMatcher.matches()) {
                    int groupCount = expMatcher.groupCount();
                    String key = "";
                    if (groupCount == 0) {
                        key = files[i].getName();
                    } else {
                        key = expMatcher.group(1);
                        for (int j = 1; j < groupCount; j++) {
                            key = key + "_" + expMatcher.group(j + 1);
                        }
                    }
                    Experiment experiment = experimentMap.get(key);
                    if (experiment == null) {
                        experiment = new Experiment();
                        experimentMap.put(key, experiment);
                        System.out.println("Added key " + key);
                    }
                    parseFile(files[i], experiment, dataPattern, spec.getKeyArray(),spec.getMulitpleDataValues());
                } else {
                    System.out.println("ignore file " + files[i].getAbsolutePath());
                }
            }
        }
    }

    public void parseFile(File fileName, Experiment experiment, Pattern pattern, String[] keys, boolean multipleDataValues)
            throws Exception {
        String line = null;
        try {
            BufferedReader br = new BufferedReader(new FileReader(fileName));
            line = br.readLine();
            while (line != null) {
                line = line.trim();
                Matcher matcher = pattern.matcher(line);

                if (matcher.matches()) {
                    int i = 1;
                    for (String key : keys) {
                        String strval = matcher.group(i).trim();
                        
                        if(multipleDataValues){
                            String[] datavalues = strval.split("\\s+");
                            for(String dataVal:datavalues){
                                double val;
                                try {
                                    val = Double.parseDouble(dataVal);
                                    if(val < 0){
                                        System.out.println("Ignoring negative value " + val);
                                        continue;
                                    }
                                    experiment.addDatapoint(key, val);

                                } catch (Throwable e) {
                                    //throw new Exception(e);
                                    System.out.println(e.getMessage());
                                }
                            }
                        }else{
                            double val = Double.parseDouble(strval);
                            if(val < 0){
                                System.out.println("Ignoring negative value " + line);
                                break;
                            }
                            experiment.addDatapoint(key, val);
                        }
                        i++;
                    }
                } else {
                    if (printUnporcessedLines && !line.contains("#")) {
                        System.out.println("Can not handle " + line);
                    }
                }
                line = br.readLine();
            }
            br.close();
        } catch (Throwable e) {
            throw new Exception(e);
        }
    }

    // public class ParseSpec {
    // Pattern filepattern;
    // Pattern dataPattern;
    // String[] keys;
    // }


}